iceoryx2 请求响应模式:流式响应与连接生命周期
请求响应是仅次于发布订阅的常用通信模型,但传统实现里「一问一答」的模式拿到机器人控制场景常常不够用:客户端请求导航到某个位置,服务端需要一路持续回报当前位置,直到到达或受阻。iceoryx2 的请求响应模式在传统语义上加了响应流——服务器可以连续发送响应,任何一方可随时终止流。本文以官方示例(App 控制 Larry 机器人自动导航)为线索,介绍 C++ 客户端与服务器的完整实现,以及连接生命周期管理的几个关键细节。
模型语义
- 一个请求对应一串响应,服务器按需持续发送;
- 任何一方都可以终止流:客户端销毁
pending_response对象即通知服务器停止发送; - 连接状态可查询,双方都能检测对端退出并及时清理资源。
客户端实现
cpp
#include "iceoryx2.hpp"
using namespace iox2;
// 1. 创建节点
auto node = NodeBuilder().create<ServiceType::Ipc>().value();
// 2. 创建服务并指定请求/响应数据类型
auto service = node.service_builder(ServiceName::create("autopilot").value())
.request_response<Position, State>()
.open_or_create()
.value();
// 3. 创建客户端端口
auto client = service.client_builder().create().value();
// 4. 发送请求
auto request = client.loan_uninit().value(); // 借出未初始化的请求内存
auto initialized_request = request.write_payload(Position{{123.456F, 789.1F}});
auto pending_response = send(std::move(initialized_request)).value();
// 5. 事件循环处理响应
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
while (true) {
auto position = pending_response.receive().value(); // 接收响应数据
if (position.has_value()) {
show_larry_position_in_app(position.value()); // 显示当前位置
} else {
break; // 本轮无更多数据
}
// 检查连接状态
if (!pending_response.is_connected()) {
if (is_at_destination(position)) {
show_larry_arrived_popup_in_app(); // 到达目的地
} else {
show_larry_encountered_obstacle_in_app(); // 中途受阻
}
}
}
} 几个关键点:
send返回的pending_response对象管理整个响应流的生命周期——它存活期间流就保持打开,销毁即取消;receive()返回空值表示本轮数据取完,不是流结束;流是否结束看is_connected();- 断开时根据最后一个响应判断是到达目的地还是遇到障碍。
服务器实现
cpp
auto node = NodeBuilder().create<ServiceType::Ipc>().value();
auto service = node.service_builder(ServiceName::create("autopilot").value())
.request_response<Position, State>()
.open_or_create()
.value();
auto server = service.server_builder().create().value();
// 接收请求,active_request 管理该请求的响应流
auto active_request = server.receive().value();
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
// 检查是否有新请求
if ( !active_request.has_value() ) {
active_request = server.receive().value();
if ( active_request.has_value() ) {
drive_to_position(active_request); // 开始向目标位置行驶
}
}
// 处理活动请求
if ( active_request.has_value() ) {
if ( !active_request->is_connected() ) { // 客户端断开连接
stop_driving();
active_request.reset(); // 清空活动请求
} else if ( arrived_at_destination() ) { // 到达目的地
active_request.reset();
} else { // 正常行驶中,发送状态更新
auto response = active_request->loan_uninit().value();
auto initialized_response = response.write_payload(get_current_state());
send(std::move(initialized_response)).value();
}
}
} 服务器侧的生命周期管理:
- 客户端断开:
active_request->is_connected()为假时停止行驶并reset()清空,释放该请求的资源; - 任务完成:到达目的地后同样
reset(),等待下一个请求; - 正常处理:每个周期借出响应内存、写入当前状态、发送。
关键机制
- 双工流通信:请求发出后连接保持打开,服务器可以持续推送状态更新,客户端不需要反复发起新请求;
- RAII 管理资源:
pending_response与active_request分别在两端管理流的生命周期,对象销毁即通知对端; - 非阻塞轮询:配合
node.wait的周期循环,不阻塞线程,可与其他通信模式在同一节点共存; - 双向断连检测:连接断开时双方都能通过
is_connected()感知并清理。
这套模式适合需要持续状态反馈的控制场景:机器人导航、远程监控、长任务的进度推送。
要点
- iceoryx2 的请求响应是流式的:一个请求,一串响应,双方都可终止
pending_response(客户端)和active_request(服务器)是流的两端句柄,销毁即断流receive()空值只表示本轮取完,流结束以is_connected()为准- 客户端取消流 = 销毁
pending_response,服务器会收到断连并自行停止